/*
 * EnumConverter.java
 * 
 * Classe responsavel por obter o valor do enum e mostrar em um render JSF e
 * tambem obter um enum e setar em alguma propriedade do mesmo tipo no
 * ManagedBean
 * 
 * $Id: EnumConverter.java 9941 2011-03-28 20:57:01Z helder.alves $
 * 
 * Todos os direitos reservados ao Banco do Nordeste do Brasil (BNB)
 */

package iface.aplicativo.apresentacao.converter;

import java.util.Collection;
import java.util.List;

import javax.el.ValueExpression;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.convert.ConverterException;
import javax.faces.convert.FacesConverter;

/**
 * @class EnumConverter
 * 
 *        Classe responsavel por obter o valor do enum e mostrar em um render
 *        JSF e tambem obter um enum e setar em alguma propriedade do mesmo tipo
 *        no ManagedBean
 * 
 */
@FacesConverter(value = "enumConverter")
public class EnumConverter implements Converter {

	public Object getAsObject(FacesContext contexto, UIComponent componente,
			String valor) {
		Object retorno = null;
		ValueExpression binding = componente.getValueExpression("value");
		Class enumType = binding.getType(contexto.getELContext());
		if (enumType.isEnum()) {
			// Se for um unico elemento selecionado
			retorno = getEnum(enumType, valor);
		} else {
			// Se for um elemento selecionado a partir de um array
			retorno = getEnumDoArray(contexto, componente, valor);
		}
		return retorno;
	}

	/**
	 * Retorna o resultado convertido quando um unico Enum estiver sendo
	 * selecionado.
	 * 
	 * @param enumType
	 * @param valor
	 * @return
	 */
	private Object getEnum(Class enumType, String valor) {
		return Enum.valueOf(enumType, valor);
	}

	/**
	 * Retorna o resultado convertido quando um Enum tiver sido selecionado a
	 * partir de uma lista de selecao multipla.
	 * 
	 * @param contexto
	 * @param componente
	 * @param valor
	 * @return
	 */
	private Object getEnumDoArray(FacesContext contexto,
			UIComponent componente, String valor) {
		// Encontrar o selectItens para obter a classe do enum.
		List<UIComponent> filhos = componente.getChildren();
		for (UIComponent componenteFilho : filhos) {
			ValueExpression binding = componenteFilho
					.getValueExpression("value");
			Class enumType = binding.getType(contexto.getELContext());
			// Array de enums: utilizar o componentType.
			if (enumType.isArray() && enumType.getComponentType().isEnum()) {
				enumType = enumType.getComponentType();
			} else {
				Object valBinding = binding.getValue(contexto.getELContext());
				// Colecao de enums, obter o tipo do primeiro elemento.
				if (valBinding instanceof Collection) {
					enumType = ((Collection) valBinding).iterator().next()
							.getClass();
				}
			}
			return Enum.valueOf(enumType, valor);
		}
		throw new ConverterException(
				"Nao foi encontrado selectItens com valores de enums!");
	}

	public String getAsString(FacesContext arg0, UIComponent arg1, Object object) {
		String retorno = "";
		if (object != null) {
			if (object instanceof String) {
				retorno = (String) object;
			} else {
				Enum enumType = (Enum) object;
				retorno = enumType.name();
			}
		}
		return retorno;
	}
}